﻿using BlueWind.Mediator.ServiceContracts.Exceptions;
using BlueWind.Mediator.ServiceContracts.Interfaces;
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Threading;

namespace BlueWind.Mediator.ServiceContracts
{
    public delegate void Callback(String from, String room, BwMessage message, MessageType messageType);

    public delegate void ReceivedEventHandler(String from, String room, BwMessage message, MessageType messageType);

    [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
    public class Colleague : IColleague
    {
        private List<String> chatRoomList;
        private BwConnection connection;

        public BwConnection Connection
        {
            get { return connection; }
        }

        private InstanceContext context;
        private Boolean isAuthenticated = false;
        private IDomainRepository repository;
        private BwUser user;
        private DuplexChannelFactory<IMediatorPrototypeManager> mediatorFactory;
        private DuplexChannelFactory<IDomainRepository> repositoryFactory;

        public Colleague()
        {
            //WSDualHttpBinding httpBinding = new WSDualHttpBinding();
            //httpBinding.ReaderQuotas.MaxStringContentLength = Int32.MaxValue;
            //httpBinding.MaxReceivedMessageSize = Int32.MaxValue;

            //httpBinding.MaxBufferPoolSize = Int32.MaxValue;
            //httpBinding.ReaderQuotas.MaxDepth = Int32.MaxValue;
            //httpBinding.ReaderQuotas.MaxArrayLength = Int32.MaxValue;
            //httpBinding.ReaderQuotas.MaxBytesPerRead = Int32.MaxValue;
            //httpBinding.CloseTimeout = new TimeSpan(5, 0, 0);
            //httpBinding.OpenTimeout = new TimeSpan(5, 0, 0);
            //httpBinding.ReceiveTimeout = new TimeSpan(0, 30, 0);
            //httpBinding.SendTimeout = new TimeSpan(0, 30, 0);

            //httpBinding.Security = new WSDualHttpSecurity();
            //httpBinding.Security.Mode = WSDualHttpSecurityMode.None;

            NetTcpBinding binding = new NetTcpBinding();
            binding.ReaderQuotas.MaxStringContentLength = Int32.MaxValue;
            binding.MaxReceivedMessageSize = Int32.MaxValue;
            binding.MaxBufferSize = Int32.MaxValue;
            binding.MaxBufferPoolSize = Int32.MaxValue;
            binding.ReaderQuotas.MaxDepth = Int32.MaxValue;
            binding.ReaderQuotas.MaxArrayLength = Int32.MaxValue;
            binding.ReaderQuotas.MaxBytesPerRead = Int32.MaxValue;
            binding.CloseTimeout = new TimeSpan(5, 0, 0);
            binding.OpenTimeout = new TimeSpan(5, 0, 0);
            binding.ReceiveTimeout = new TimeSpan(0, 30, 0);
            binding.SendTimeout = new TimeSpan(0, 30, 0);

            binding.Security = new NetTcpSecurity();
            binding.Security.Mode = SecurityMode.None;

            chatRoomList = new List<String>();
            this.user = new BwUser();
            context = new InstanceContext(this);
            mediatorFactory = new DuplexChannelFactory<IMediatorPrototypeManager>(context, binding, new EndpointAddress(ServerInfo.ServerAddress + "MediatorPrototypeManager"));

            // mediatorFactory  = new DuplexChannelFactory<IMediatorPrototypeManager>(context, httpBinding, new EndpointAddress(ServerRepository.ServerAddress + "MediatorPrototypeManager"));
            ThreadPool.QueueUserWorkItem(new WaitCallback(
                 (obj) =>
                 {
                     mediatorManager = mediatorFactory.CreateChannel();
                     ((ICommunicationObject)mediatorManager).Faulted += new EventHandler(RefreshChannel);
                 }));

            EndpointAddress endPoint = new EndpointAddress(ServerInfo.ServerAddress + "DomainRepository");
            repositoryFactory = new DuplexChannelFactory<IDomainRepository>(context, binding, endPoint);

            // repositoryFactory = new DuplexChannelFactory<IDomainRepository>(context, httpBinding, endPoint);
            repository = (repositoryFactory).CreateChannel();
            ((ICommunicationObject)repository).Faulted += new EventHandler(RefreshChannel);
        }

        private void RefreshChannel(object sender, EventArgs e)
        {
            if (sender is IMediatorPrototypeManager)
            {
                mediatorManager = mediatorFactory.CreateChannel();
            }
            else if (sender is IDomainRepository)
            {
                repository = (repositoryFactory).CreateChannel();
            }
        }

        public event ReceivedEventHandler ReceivedHandler;

        public List<String> ChatRoomList
        {
            get
            {
                return chatRoomList;
            }

            set
            {
                chatRoomList = value;
            }
        }

        public Boolean IsAuthenticated
        {
            get { return isAuthenticated; }
        }

        public IDomainRepository Repository { get { return repository; } }

        public BwUser User { get { return user; } }

        private IMediatorPrototypeManager mediatorManager { get; set; }

        public void CreateRoom(String from, String to)
        {
            if (!mediatorManager.CheckMediatorExist(from, to)) mediatorManager.CreateNewMediator(from, to);
        }

        public void DestroyInstance()
        {
            //foreach (String mediatorName in chatRoomList)
            //{
            //    UnRegister(mediatorName);
            //}
            //((IDisposable)repository).Dispose();
            throw new LoginCollisionException();
        }

        public Boolean Login(String userName, String password)
        {
            if (!isAuthenticated)
            {
                AuthenticationObject value = repository.Authenticate(userName, password);
                if (value.Authenticated)
                {
                    isAuthenticated = true;
                    user = value.User;
                    connection = value.Connection;
                    return true;
                }
            }
            return false;
        }

        public void Logout()
        {
            if (isAuthenticated)
            {
                foreach (String tmp in ChatRoomList)
                {
                    UnRegister(tmp);
                }
                chatRoomList.Clear();
                repository.UnAuthenticate(user.UserName, user.Password, connection);
                isAuthenticated = false;
            }
        }

        public void Receive(String from, String room, BwMessage message, MessageType messageType)
        {
            if (ReceivedHandler != null)
                ReceivedHandler(from, room, message, messageType);
        }

        public void Register(String from, String room, Boolean isClassroom)
        {
            mediatorManager.Register(from, room, isClassroom);
            chatRoomList.Add(room);
        }

        public void Register(String from, String to)
        {
            mediatorManager.Register(this.User.UserName, to);
            chatRoomList.Add((new HandSakeBase(this.User.UserName, to)).HandSakeName);
        }

        public void Send(String room, BwMessage message, MessageType messageType)
        {
            mediatorManager.Send(user.UserName, room, message, messageType);
        }

        public void UnRegister(string room)
        {
            mediatorManager.UnRegisterToExistMediator(room, User.UserName);
        }

        public void UnRegister(string from, string to)
        {
            if (!mediatorManager.CheckMediatorExist(from, to))
                chatRoomList.Remove((new HandSakeBase(from, to).HandSakeName));
            mediatorManager.RegisterToExistMediator(from, (new HandSakeBase(from, to)).HandSakeName);
        }
    }
}